﻿using System;
using System.Linq.Expressions;
using System.Reflection;
using Loki.Utils;
using NUnit.Framework;

namespace Loki.Core.Test.Events
{
    public class EventsTests : AssertionHelper
    {
        [Test]
        public void ShouldHandleEventWhenBothReferencesAreAlive()
        {
            var L_Observed = new DummyObserved();
            var L_Observer = new DummyObserver(L_Observed);
            L_Observed.Property = "Value1";
            L_Observed.Property = "Value2";

            Assert.AreEqual(2, L_Observer.Count);
        }

        [Test]
        public void TestExpression()
        {
            var source = new DummyObserved();
            source.Property = "Value1";

            var dest = new DummyObserved();

            PropertyInfo property = ExpressionHelper.GetProperty<DummyObserved, string>(x => x.Property);
            var parameter = Expression.Parameter(property.DeclaringType);
            var parameterDest = Expression.Parameter(property.DeclaringType);
            var valueGet = Expression.Property(parameter, property);
            var valueSet = Expression.Property(parameterDest, property);
            var assign = Expression.Assign(valueSet, valueGet);
            var lambda = Expression.Lambda(assign, parameter, parameterDest);
            var method = lambda.Compile();
            method.DynamicInvoke(source, dest);

            Expect(source.Property, Is.EqualTo(dest.Property));
        }

        [Test]
        public void ShouldAllowSubscriberReferenceToBeCollected()
        {
            var L_Observed = new DummyObserved();
            var L_ObserverReference = null as WeakReference;
            new Action(() =>
            {
                // Run this in a delegate to that the local variable gets garbage collected
                var L_Observer = new DummyObserver(L_Observed);
                L_Observed.Property = "Value1";
                L_Observed.Property = "Value2";

                Assert.AreEqual(2, L_Observer.Count);
                L_ObserverReference = new WeakReference(L_Observer);
            })();

            GC.Collect();
            Toolkit.Events.RemoveCollectedEntries();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Assert.IsNull(L_ObserverReference.Target);
        }

        /*[Test]
        public void ShouldAllowSynchronizeReferenceToBeCollected()
        {
            var L_LongLife = new BindableCollection<DummyObserved>();
            var L_ObserverReference = null as WeakReference;
            new Action(() =>
            {
                var L_Observer = new BindableCollection<DummyObserved>();
                L_Observer.Synchronize(
                    L_LongLife,
                    (o, n) =>
                    {
                        n.Property = o.Property;
                    },
                    (o, n) =>
                    {
                        return o.Property == n.Property;
                    },
                    o => o.Property);
                L_LongLife.Add(new DummyObserved() { Property = "value1" });
                L_LongLife.Add(new DummyObserved() { Property = "value2" });

                // Wait for async execution
                Thread.Sleep(1000);

                Expect(L_Observer.Count, Is.EqualTo(2));
                L_ObserverReference = new WeakReference(L_Observer);
            })();

            GC.Collect();
            ToolKit.Event.RemoveCollectedEntries();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Assert.IsNull(L_ObserverReference.Target);
        }*/
    }
}